package com.flow.service.provider.toleration.computer.service.impl;

import com.flow.common.facade.experiment.apply.immutable.ApplyTypeImmutable;
import com.flow.common.facade.toleration.computer.immutable.ComputerOccupancyStatusImmutable;
import com.flow.common.facade.toleration.computer.immutable.ComputerStatusImmutable;
import com.flow.framework.common.error.SystemErrorCode;
import com.flow.framework.common.exception.CheckedException;
import com.flow.framework.lock.enumeration.ILockKeyEnum;
import com.flow.service.facade.toleration.TolerationErrorCode;
import com.flow.service.provider.toleration.apply.service.IResourceApplyService;
import com.flow.service.provider.toleration.computer.persistence.service.IComputerPoService;
import com.flow.service.provider.toleration.computer.pojo.po.Computer;
import com.flow.service.provider.toleration.enumeration.ComputerLockKeyEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 电脑申请服务实现
 *
 * @author luoguopiao
 * @version 0.0.1
 * @date 2023/5/2
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ComputerApplyServiceImpl implements IResourceApplyService {

    private final IComputerPoService computerPoService;

    /**
     * 检查资源是否可以被申请
     *
     * @param type       申请类型
     * @param resourceId 资源id
     */
    @Override
    public void check(String type, String resourceId) {
        Computer computer = computerPoService.getById(resourceId, false);
        String computerOccupancyStatus = computer.getComputerOccupancyStatus();
        if (ApplyTypeImmutable.COMPUTER_RECYCLE_SALE_APPLY.equals(type)) {
            String computerStatus = computer.getComputerStatus();
            if (ComputerStatusImmutable.RECYCLE_SOLD.equals(computerStatus)
                    || !ComputerOccupancyStatusImmutable.IDLE.equals(computerOccupancyStatus)) {
                log.error("computer status expect not recycle sold and computer occupancy status expect idle, " +
                        "current status : {}, computer occupancy status : {}", computerStatus, computerOccupancyStatus);
                throw new CheckedException(TolerationErrorCode.COMPUTER_STATUS_ERROR);
            }
        } else if (ApplyTypeImmutable.COMPUTER_USE_APPLY.equals(type)) {
            if (!ComputerOccupancyStatusImmutable.IDLE.equals(computerOccupancyStatus)) {
                log.error("computer occupancy status expect idle, current status : {}", computerOccupancyStatus);
                throw new CheckedException(TolerationErrorCode.COMPUTER_OCCUPANCY_STATUS_ERROR);
            }
        } else if (ApplyTypeImmutable.COMPUTER_BACK_APPLY.equals(type)) {
            if (!ComputerOccupancyStatusImmutable.IN_USE.equals(computerOccupancyStatus)) {
                log.error("computer occupancy status expect idle, current status : {}", computerOccupancyStatus);
                throw new CheckedException(TolerationErrorCode.COMPUTER_OCCUPANCY_STATUS_ERROR);
            }
        } else {
            log.error("can't support apply type. apply type : {}", type);
            throw new CheckedException(SystemErrorCode.UNEXPECTED_ERROR);
        }
    }

    /**
     * 获取分布式锁枚举，用于资源修改时加锁
     *
     * @param type 申请类型
     * @return
     */
    @Override
    public ILockKeyEnum getLockEnum(String type) {
        if (ApplyTypeImmutable.COMPUTER_RECYCLE_SALE_APPLY.equals(type)) {
            return ComputerLockKeyEnum.COMPUTER_STATUS_CHECK_LOCK_KEY;
        } else if (ApplyTypeImmutable.COMPUTER_USE_APPLY.equals(type)
                || ApplyTypeImmutable.COMPUTER_BACK_APPLY.equals(type)) {
            return ComputerLockKeyEnum.COMPUTER_OCCUPANCY_STATUS_CHECK_LOCK_KEY;
        } else {
            log.error("can't support apply type. apply type : {}", type);
            throw new CheckedException(SystemErrorCode.UNEXPECTED_ERROR);
        }
    }

    /**
     * 修改资源状态为申请中
     *
     * @param type       申请类型
     * @param resourceId resourceId
     */
    @Override
    public void updateResourceApplying(String type, String resourceId) {
        computerPoService.updateResourceApplying(resourceId);
    }

    /**
     * 申请结果回调
     *
     * @param type       申请类型
     * @param success    是否申请成功
     * @param resourceId resourceId
     */
    @Override
    public void applyResultCallback(String type, boolean success, String resourceId) {
        Computer computerInDb = computerPoService.getById(resourceId, false);
        String computerOccupancyStatus = computerInDb.getComputerOccupancyStatus();
        if (ComputerOccupancyStatusImmutable.IN_USE.equals(computerOccupancyStatus)) {
            log.warn("computer occupancy status expect in use, current status : {}", computerOccupancyStatus);
            return;
        }
        if (!ComputerOccupancyStatusImmutable.APPLYING.equals(computerOccupancyStatus)) {
            log.error("computer occupancy status expect applying, current status : {}", computerOccupancyStatus);
            throw new CheckedException(TolerationErrorCode.COMPUTER_OCCUPANCY_STATUS_ERROR);
        }
        Computer updateComputer = new Computer();
        updateComputer.setId(resourceId);
        if (!success) {
            updateComputer.setComputerOccupancyStatus(ComputerOccupancyStatusImmutable.IDLE);
        } else {
            if (ApplyTypeImmutable.COMPUTER_RECYCLE_SALE_APPLY.equals(type)) {
                updateComputer.setComputerOccupancyStatus(ComputerOccupancyStatusImmutable.IDLE);
                updateComputer.setComputerStatus(ComputerStatusImmutable.RECYCLE_SOLD);
            } else if (ApplyTypeImmutable.COMPUTER_USE_APPLY.equals(type)) {
                updateComputer.setComputerOccupancyStatus(ComputerOccupancyStatusImmutable.IN_USE);
            } else if (ApplyTypeImmutable.COMPUTER_BACK_APPLY.equals(type)) {
                updateComputer.setComputerOccupancyStatus(ComputerOccupancyStatusImmutable.IDLE);
            } else {
                log.error("can't support apply type. apply type : {}", type);
                throw new CheckedException(SystemErrorCode.UNEXPECTED_ERROR);
            }
        }
        computerPoService.updateById(updateComputer);
    }

    /**
     * 获取代理的类型，即实际使用时会根据该类型获取被代理的对象
     *
     * @return 类型
     */
    @Override
    public String[] getTypes() {
        return new String[]{
                ApplyTypeImmutable.COMPUTER_USE_APPLY,
                ApplyTypeImmutable.COMPUTER_BACK_APPLY,
                ApplyTypeImmutable.COMPUTER_RECYCLE_SALE_APPLY
        };
    }
}